home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / GNU_KIT / DISK8.ZIP / src / makest / arscan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-08  |  10.9 KB  |  475 lines

  1. /* Library function for scanning an archive file.
  2.    Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* On the sun386i and in System V rel 3, ar.h defines two different archive
  19.    formats depending upon whether you have defined PORTAR (normal) or PORT5AR
  20.    (System V Release 1).  There is no default, one or the other must be defined
  21.    to have a nonzero value.  */
  22.  
  23. #if (defined(sun386) || defined(USGr3) || defined(HPUX) \
  24.      && !defined(PORTAR) && !defined(PORT5AR))
  25. #define PORTAR 1
  26. #endif
  27.  
  28. #ifdef atarist
  29. #include <gnu-ar.h>
  30. #else
  31. #include <ar.h>
  32. #endif
  33. #include <stdio.h>
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36.  
  37. #ifdef USG
  38. #include <fcntl.h>
  39. #else
  40. #include <sys/file.h>
  41. #endif
  42.  
  43. #if    (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) \
  44.      || defined (_POSIX_SOURCE))
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #define    ANSI_STRING
  48. #else    /* No standard headers.  */
  49.  
  50. #ifdef    USG
  51.  
  52. #include <string.h>
  53. #include <memory.h>
  54. #define    ANSI_STRING
  55.  
  56. #else    /* Not USG.  */
  57. #include <strings.h>
  58.  
  59. extern int bcmp ();
  60. extern void bzero (), bcopy ();
  61.  
  62. #endif    /* USG.  */
  63.  
  64. extern char *malloc (), *realloc ();
  65. extern void free ();
  66.  
  67. #endif    /* Standard headers.  */
  68.  
  69. #ifdef    ANSI_STRING
  70. #define    index(s, c)    strchr((s), (c))
  71. #define    rindex(s, c)    strrchr((s), (c))
  72.  
  73. #define bcmp(s1, s2, n)    memcmp ((s1), (s2), (n))
  74. #define bzero(s, n)    memset ((s), 0, (n))
  75. #define bcopy(s, d, n)    memcpy ((d), (s), (n))
  76. #endif    ANSI_STRING
  77. #undef    ANSI_STRING
  78.  
  79.  
  80. #ifndef    AIAMAG
  81. #if    (defined(APOLLO) || defined(HPUX) || defined(hpux) || \
  82.      (PORTAR == 1 && (defined(USGr3) || defined(u3b2) || defined(sun386))))
  83. #define    AR_NAMELEN    14
  84. #define    AR_TRAILING_SLASH    /* Member names have a trailing slash.  */
  85. #else
  86. #define    AR_NAMELEN    15
  87. #endif
  88. #else    /* AIX.  */
  89. #define    AR_NAMELEN    255
  90. #endif
  91.  
  92. #if    defined(__GNU_LIBRARY__) || defined(_POSIX_SOURCE) || defined(_IBMR2)
  93. #include <unistd.h>
  94. #else
  95. extern int read (), close (), write (), fstat ();
  96. extern long int lseek (), atol ();
  97. extern int atoi ();
  98. #endif
  99.  
  100. /* Takes three arguments ARCHIVE, FUNCTION and ARG.
  101.  
  102.    Open the archive named ARCHIVE, find its members one by one,
  103.    and for each one call FUNCTION with the following arguments:
  104.      archive file descriptor for reading the data,
  105.      member name,
  106.      member header position in file,
  107.      member data position in file,
  108.      member data size,
  109.      member date,
  110.      member uid,
  111.      member gid,
  112.      member protection mode,
  113.      ARG.
  114.  
  115.    The descriptor is poised to read the data of the member
  116.    when FUNCTION is called.  It does not matter how much
  117.    data FUNCTION reads.
  118.  
  119.    If FUNCTION returns nonzero, we immediately return
  120.    what FUNCTION returned.
  121.  
  122.    Returns -1 if archive does not exist,
  123.    Returns -2 if archive has invalid format.
  124.    Returns 0 if have scanned successfully.  */
  125.  
  126. long int
  127. ar_scan (archive, function, arg)
  128.      char *archive;
  129.      long int (*function) ();
  130.      long int arg;
  131. {
  132. #ifdef AIAMAG
  133.   FL_HDR fl_header;
  134. #endif
  135.   register int desc = open (archive, O_RDONLY, 0);
  136.   if (desc < 0)
  137.     return -1;
  138. #ifdef SARMAG
  139.   {
  140.     char buf[SARMAG];
  141.     register int nread = read (desc, buf, SARMAG);
  142.     if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
  143.       {
  144.     (void) close (desc);
  145.     return -2;
  146.       }
  147.   }
  148. #else
  149. #ifdef AIAMAG
  150.   {
  151.     register int nread = read (desc, &fl_header, FL_HSZ);
  152.     if (nread != FL_HSZ || bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
  153.       {
  154.     (void) close (desc);
  155.     return -2;
  156.       }
  157.   }
  158. #else
  159.   {
  160. #ifndef M_XENIX
  161.     int buf;
  162. #else
  163.     unsigned short int buf;
  164. #endif
  165.     register int nread = read(desc, &buf, sizeof (buf));
  166.     if (nread != sizeof (buf) || buf != ARMAG)
  167.       {
  168.     (void) close (desc);
  169.     return -2;
  170.       }
  171.   }
  172. #endif
  173. #endif
  174.  
  175.   /* Now find the members one by one.  */
  176.   {
  177. #ifdef SARMAG
  178.     register long int member_offset = SARMAG;
  179. #else
  180. #ifdef AIAMAG
  181.     long int member_offset;
  182.     long int last_member_offset;
  183.  
  184.     sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
  185.     sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
  186. #else
  187. #ifndef    M_XENIX
  188.     register long int member_offset = sizeof (int);
  189. #else    /* Xenix.  */
  190.     register long int member_offset = sizeof (unsigned short int);
  191. #endif    /* Not Xenix.  */
  192. #endif
  193. #endif
  194.  
  195.     while (1)
  196.       {
  197.     register int nread;
  198.     struct ar_hdr member_header;
  199. #ifdef AIAMAG
  200.     char name[AR_NAMELEN + 1];
  201.     int name_len;
  202.     long int dateval;
  203.     int uidval, gidval;
  204.     long int data_offset;
  205. #else
  206.     char name[sizeof member_header.ar_name + 1];
  207. #endif
  208.     long int eltsize;
  209.     int eltmode;
  210.     long int fnval;
  211.  
  212.     if (lseek (desc, member_offset, 0) < 0)
  213.       {
  214.         (void) close (desc);
  215.         return -2;
  216.       }
  217.  
  218. #ifdef AIAMAG
  219. #define    AR_MEMHDR    \
  220.     (sizeof (member_header) - sizeof (member_header._ar_name))
  221.     nread = read (desc, (char *) &member_header, AR_MEMHDR);
  222.  
  223.     if (nread != AR_MEMHDR)
  224.       {
  225.         (void) close (desc);
  226.         return -2;
  227.       }
  228.  
  229.     sscanf (member_header.ar_namlen, "%4d", &name_len);
  230.     nread = read (desc, name, name_len);
  231.  
  232.     if (nread != name_len)
  233.       {
  234.         (void) close (desc);
  235.         return -2;
  236.       }
  237.     
  238.     name[name_len] = 0;
  239.  
  240.     sscanf (member_header.ar_date, "%12ld", &dateval);
  241.     sscanf (member_header.ar_uid, "%12d", &uidval);
  242.     sscanf (member_header.ar_gid, "%12d", &gidval);
  243.     sscanf (member_header.ar_mode, "%12o", &eltmode);
  244.     sscanf (member_header.ar_size, "%12ld", &eltsize);
  245.  
  246.     if ((data_offset = member_offset + AR_MEMHDR + name_len + 2) % 2)
  247.         ++data_offset;
  248.  
  249.     fnval =
  250.       (*function) (desc, name, member_offset, data_offset, eltsize,
  251.                dateval, uidval, gidval,
  252.                eltmode, arg);
  253.  
  254. #else
  255.     nread = read (desc, (char *) &member_header, sizeof (struct ar_hdr));
  256.     if (nread == 0)
  257.       /* No data left means end of file; that is OK.  */
  258.       break;
  259.  
  260.     if (nread != sizeof (member_header)
  261. #ifdef ARFMAG
  262.         || bcmp (member_header.ar_fmag, ARFMAG, 2)
  263. #endif
  264.         )
  265.       {
  266.         (void) close (desc);
  267.         return -2;
  268.       }
  269.  
  270.     bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
  271.     {
  272.       register char *p = name + sizeof member_header.ar_name;
  273.       while (p > name && *--p == ' ')
  274.         *p = '\0';
  275. #ifdef    AR_TRAILING_SLASH
  276.       if (*p == '/')
  277.         *p = '\0';
  278. #endif
  279.     }
  280.  
  281. #ifndef    M_XENIX
  282.     sscanf (member_header.ar_mode, "%o", &eltmode);
  283.     eltsize = atol (member_header.ar_size);
  284. #else    /* Xenix.  */
  285.     eltmode = (unsigned short int) member_header.ar_mode;
  286.     eltsize = member_header.ar_size;
  287. #endif    /* Not Xenix.  */
  288.  
  289.     fnval =
  290.       (*function) (desc, name, member_offset,
  291.                member_offset + sizeof (member_header), eltsize,
  292. #ifndef    M_XENIX
  293.                atol (member_header.ar_date),
  294.                atoi (member_header.ar_uid),
  295.                atoi (member_header.ar_gid),
  296. #else    /* Xenix.  */
  297.                member_header.ar_date,
  298.                member_header.ar_uid,
  299.                member_header.ar_gid,
  300. #endif    /* Not Xenix.  */
  301.                eltmode, arg);
  302.  
  303. #endif  /* Not AIAMAG */
  304.  
  305.     if (fnval)
  306.       {
  307.         (void) close (desc);
  308.         return fnval;
  309.       }
  310.  
  311. #ifdef AIAMAG
  312.     if (member_offset == last_member_offset) /* end of chain? */
  313.         break;
  314.  
  315.     sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
  316.  
  317.     if (lseek (desc, member_offset, 0) != member_offset)
  318.       {
  319.         (void) close (desc);
  320.         return -2;
  321.       }
  322. #else
  323.     member_offset += sizeof (member_header) + eltsize;
  324.     if (member_offset & 1) member_offset++;
  325. #endif
  326.       }
  327.   }
  328.  
  329.   close (desc);
  330.   return 0;
  331. }
  332.  
  333. /* Return nonzero iff NAME matches MEM.  If NAME is longer than
  334.    sizeof (struct ar_hdr.ar_name), MEM may be the truncated version.  */
  335.  
  336. int
  337. ar_name_equal (name, mem)
  338.      char *name, *mem;
  339. {
  340.   char *p;
  341.  
  342.   p = rindex (name, '/');
  343.   if (p != 0)
  344.     name = p + 1;
  345.  
  346. #ifndef    APOLLO
  347.  
  348.   if (!strncmp (name, mem, AR_NAMELEN))
  349.     return 1;
  350.  
  351.   if (!strncmp (name, mem, AR_NAMELEN - 2))
  352.     {
  353.       unsigned int namelen, memlen;
  354.  
  355.       namelen = strlen (name);
  356.       memlen = strlen (mem);
  357.  
  358.       if (memlen == AR_NAMELEN
  359.       && mem[AR_NAMELEN - 2] == '.' && mem[AR_NAMELEN - 1] == 'o'
  360.       && name[namelen - 2] == '.' && name[namelen -1] == 'o')
  361.     return 1;
  362.     }
  363.   return 0;
  364.  
  365. #else    /* APOLLO.  */
  366.   return !strcmp (name, mem);
  367. #endif
  368. }
  369.  
  370. /* ARGSUSED */
  371. static long int
  372. ar_member_pos (desc, mem, hdrpos, datapos, size, date, uid, gid, mode, name)
  373.      int desc;
  374.      char *mem;
  375.      long int hdrpos, datapos, size, date;
  376.      int uid, gid, mode;
  377.      char *name;
  378. {
  379.   if (!ar_name_equal (name, mem))
  380.     return 0;
  381.   return hdrpos;
  382. }
  383.  
  384. /* Set date of member MEMNAME in archive ARNAME to current time.
  385.    Returns 0 if successful,
  386.    -1 if file ARNAME does not exist,
  387.    -2 if not a valid archive,
  388.    -3 if other random system call error (including file read-only),
  389.    1 if valid but member MEMNAME does not exist.  */
  390.  
  391. int
  392. ar_member_touch (arname, memname)
  393.      char *arname, *memname;
  394. {
  395.   register long int pos = ar_scan (arname, ar_member_pos, (long int) memname);
  396.   register int fd;
  397.   struct ar_hdr ar_hdr;
  398.   register int i;
  399.   extern int errno;
  400.   struct stat statbuf;
  401.  
  402.   if (pos < 0)
  403.     return (int) pos;
  404.   if (!pos)
  405.     return 1;
  406.  
  407.   fd = open (arname, O_RDWR, 0666);
  408.   if (fd < 0)
  409.     return -3;
  410.   /* Read in this member's header */
  411.   if (lseek (fd, pos, 0) < 0)
  412.     goto lose;
  413.   if (sizeof ar_hdr != read (fd, (char *) &ar_hdr, sizeof ar_hdr))
  414.     goto lose;
  415.   /* Write back the header, thus touching the archive file.  */
  416.   if (lseek (fd, pos, 0) < 0)
  417.     goto lose;
  418.   if (sizeof ar_hdr != write (fd, (char *) &ar_hdr, sizeof ar_hdr))
  419.     goto lose;
  420.   /* The file's mtime is the time we we want.  */
  421.   fstat (fd, &statbuf);
  422. #if defined(ARFMAG) || defined(AIAMAG)
  423.   /* Advance member's time to that time */
  424.   for (i = 0; i < sizeof ar_hdr.ar_date; i++)
  425.     ar_hdr.ar_date[i] = ' ';
  426.   sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
  427. #ifdef AIAMAG
  428.   ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
  429. #endif
  430. #else
  431.   ar_hdr.ar_date = statbuf.st_mtime;
  432. #endif
  433.   /* Write back this member's header */
  434.   if (lseek (fd, pos, 0) < 0)
  435.     goto lose;
  436.   if (sizeof ar_hdr != write (fd, (char *) &ar_hdr, sizeof ar_hdr))
  437.     goto lose;
  438.   close (fd);
  439.   return 0;
  440.  
  441.  lose:
  442.   i = errno;
  443.   close (fd);
  444.   errno = i;
  445.   return -3;
  446. }
  447.  
  448. #ifdef TEST
  449.  
  450. long int
  451. describe_member (desc, name, hdrpos, datapos, size, date, uid, gid, mode)
  452.      int desc;
  453.      char *name;
  454.      long int hdrpos, datapos, size, date;
  455.      int uid, gid, mode;
  456. {
  457.   extern char *ctime ();
  458.  
  459.   printf ("Member %s: %ld bytes at %ld (%ld).\n", name, size, hdrpos, datapos);
  460.   printf ("  Date %s", ctime (&date));
  461.   printf ("  uid = %d, gid = %d, mode = 0%o.\n", uid, gid, mode);
  462.  
  463.   return 0;
  464. }
  465.  
  466. main (argc, argv)
  467.      int argc;
  468.      char **argv;
  469. {
  470.   ar_scan (argv[1], describe_member);
  471.   return 0;
  472. }
  473.  
  474. #endif    /* TEST.  */
  475.